package com.agileai.bpm.service.define;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.agileai.bpm.common.ProcessDefineUtil;
import com.agileai.bpm.domain.define.Activity;
import com.agileai.bpm.domain.define.DatabaseResource;
import com.agileai.bpm.domain.define.Process;
import com.agileai.bpm.domain.define.ProcessFactory;
import com.agileai.bpm.domain.define.Transition;
import com.agileai.bpm.model.ProcessDefineDocument;
import com.agileai.bpm.model.ProcessDefineDocument.ProcessDefine;
import com.agileai.common.KeyGenerator;
import com.agileai.domain.DataParam;
import com.agileai.domain.DataRow;
import com.agileai.hotweb.common.DaoHelper;
import com.agileai.util.DateUtil;
import com.agileai.util.StringUtil;

public class DefineServiceImpl implements DefineService{
	protected DaoHelper daoHelper = null;
	public DaoHelper getDaoHelper() {
		return daoHelper;
	}
	public void setDaoHelper(DaoHelper daoHelper) {
		this.daoHelper = daoHelper;
	}
	public DefineServiceImpl(){
	
	}
	
	public void createProcess(Process process) {
		String processId =  KeyGenerator.instance().genKey();
		String processDefineXML = process.getDefineXML();
		ProcessFactory processFactory = new ProcessFactory();
		ProcessDefineDocument processDefineDocument = processFactory.createProcessDefineDocument(processDefineXML);
		ProcessDefine processDefine = processDefineDocument.getProcessDefine();
		
		DataParam param = null;
		
		String sqlNameSpace = "WF_ACTIVITY";
		String statementId = sqlNameSpace+"."+"insertActivity";
		HashMap<String,String> mappings = new HashMap<String,String>();
		
		List<Activity> activityList = process.getActivityList();
		for (int i=0;i < activityList.size();i++){
			param = new DataParam();
			Activity activity = activityList.get(i);
			String actCode = activity.getCode();
			activity.setProcessId(processId);
			String actId = KeyGenerator.instance().genKey();
			activity.setId(actId);
			packActivity(param, activity);
			ProcessDefineUtil.setActivityId(processDefine, actCode, actId,mappings);
			this.daoHelper.insertRecord(statementId, param);	
		}
		
		sqlNameSpace = "WF_TRANSITION";
		statementId = sqlNameSpace+"."+"insertTransition";
		List<Transition> transionList = process.getTransitionList();
		for (int i=0;i < transionList.size();i++){
			param = new DataParam();
			Transition transition = transionList.get(i);
			transition.setProcessId(processId);
			String transCode = transition.getCode();
			String transId = KeyGenerator.instance().genKey();
			transition.setId(transId);
			packTransition(param, transition);
			ProcessDefineUtil.setTransitionId(processDefine, transCode, transId,mappings);
			this.daoHelper.insertRecord(statementId, param);		
		}
		
		sqlNameSpace = "WF_PROCESS";
		statementId = sqlNameSpace+"."+"insertProcess";
		param = new DataParam();
		
		processDefineXML = processDefineDocument.toString(); 
		process.setDefineXML(processDefineXML);
		process.setId(processId);
		packProcess(param,process,true);
		this.daoHelper.insertRecord(statementId, param);
	}	
	public void deleteProcess(String processId) {
		String sqlNameSpace = "WF_PROCESS";
		String statementId = sqlNameSpace+"."+"deleteProcess";
		DataParam param = new DataParam();
		param.put("WFP_ID",processId);
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_ACTIVITY";
		statementId = sqlNameSpace+"."+"deleteActivitys";
		param = new DataParam();
		param.put("WFP_ID",processId);
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_TRANSITION";
		statementId = sqlNameSpace+"."+"deleteTransitions";
		param = new DataParam();
		param.put("WFP_ID", processId);
		this.daoHelper.deleteRecords(statementId, param);
	}
	private List<DataRow> queryDbConfigs(){
		String sqlNameSpace = "wfdbconfig";
		String statementId = sqlNameSpace+"."+"queryRecords";
		DataParam param = new DataParam();
		List<DataRow> result = this.daoHelper.queryRecords(statementId, param);
		return result;
	}
	private void attachExtInfomations(Process process,List<DataRow> dbConfigs){
		for (int i=0;i < dbConfigs.size();i++){
			DataRow row = dbConfigs.get(i);
			DatabaseResource resource = new DatabaseResource();
			resource.setConnectionId(row.getString("WFD_ID"));
			resource.setConnectionAlias(row.getString("WFD_ALIAS"));
			resource.setConnectionName(row.getString("WFD_NAME"));
			resource.setDbURL(row.getString("WFD_URL"));
			resource.setDriverClass(row.getString("WFD_DRIVER"));
			resource.setDriverPath(row.getString("WFD_DRIVERPATH"));
			resource.setUserId(row.getString("WFD_USER"));
			resource.setUserPwd(row.getString("WFD_PWD"));
			process.getDbResourceList().add(resource);
		}
		
	}
	public Process loadProcess(String processId) {
		Process result = null;
		String sqlNameSpace = "WF_PROCESS";
		String statementId = sqlNameSpace+"."+"retrieveProcess";
		DataParam param = new DataParam();
		param.put("WFP_ID",processId);
		DataRow dataRow = this.daoHelper.getRecord(statementId, param);
		List<DataRow> dbConfigs = queryDbConfigs();
		result = this.buildProcess(dataRow,dbConfigs);
		return result;
	}
	
	private Process buildProcess(DataRow dataRow,List<DataRow> dbConfigs){
		Process result = null;
		String defineXML = dataRow.getString("WFP_DEFINE");
		String processId = dataRow.getString("WFP_ID");
		if (!StringUtil.isNullOrEmpty(defineXML)){
			ProcessFactory processFactory = new ProcessFactory();
			result = processFactory.createProcess(defineXML);
			this.attachExtInfomations(result,dbConfigs);
			result.setId(processId);
			result.setCode(dataRow.stringValue("WFP_CODE"));
			result.setName(dataRow.stringValue("WFP_NAME"));
			result.setDesc(dataRow.stringValue("WFP_DESC"));
			result.setStatus(dataRow.stringValue("WFP_STATE"));
			result.setVersion(dataRow.stringValue("WFP_VERSION"));
			result.setCreateTime(dataRow.stringValue("WFP_CREATE_TIME"));
			result.setCreaterId(dataRow.stringValue("WFP_CREATER"));
			result.setModifyTime(dataRow.stringValue("WFP_MODIFY_TIME"));
			result.setModifier(dataRow.stringValue("WFP_MODIFIER"));
			result.setGroup(dataRow.stringValue("WFP_GROUP"));
			result.setGraphJSON(dataRow.stringValue("WFP_GRAPH"));
		}else{
			result = new Process();
			result.setId(dataRow.stringValue("WFP_ID"));
			result.setCode(dataRow.stringValue("WFP_CODE"));
			result.setName(dataRow.stringValue("WFP_NAME"));
			result.setDesc(dataRow.stringValue("WFP_DESC"));
			result.setStatus(dataRow.stringValue("WFP_STATE"));
			result.setVersion(dataRow.stringValue("WFP_VERSION"));
			result.setCreateTime(dataRow.stringValue("WFP_CREATE_TIME"));
			result.setCreaterId(dataRow.stringValue("WFP_CREATER"));
			result.setModifyTime(dataRow.stringValue("WFP_MODIFY_TIME"));
			result.setModifier(dataRow.stringValue("WFP_MODIFIER"));
			result.setGroup(dataRow.stringValue("WFP_GROUP"));
		}
		return result;
	}
	
	public List<Process> findAllProcess(){
		List<Process> result = new ArrayList<Process>();
		String sqlNameSpace = "WF_PROCESS";
		String statementId = sqlNameSpace+"."+"findAllProcess";
		DataParam param = new DataParam();
		List<DataRow> processes = this.daoHelper.queryRecords(statementId, param);
		List<DataRow> dbConfigs = queryDbConfigs();
		for (int i=0;i < processes.size();i++){
			DataRow dataRow = processes.get(i);
			Process process =  buildProcess(dataRow, dbConfigs);
			result.add(process);
		}
		return result;
	}
	
	public void updateProcess(Process process) {
		String sqlNameSpace = "WF_PROCESS";
		String statementId = sqlNameSpace+"."+"updateProcess";
		DataParam param = new DataParam();
		packProcess(param,process,false);
		
		this.daoHelper.updateRecord(statementId, param);
		
		String processId = process.getId();		
		sqlNameSpace = "WF_ACTIVITY";
		statementId = sqlNameSpace+"."+"deleteActivitys";
		param = new DataParam();
		param.put("WFP_ID",processId);
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_TRANSITION";
		statementId = sqlNameSpace+"."+"deleteTransitions";
		param = new DataParam();
		param.put("WFP_ID", processId);
		this.daoHelper.deleteRecords(statementId, param);
		
		sqlNameSpace = "WF_ACTIVITY";
		List<Activity> activityList = process.getActivityList();
		for (int i=0;i < activityList.size();i++){
			param = new DataParam();
			Activity activity = activityList.get(i);
			activity.setProcessId(processId);
			statementId = sqlNameSpace+"."+"insertActivity";
			if (StringUtil.isNullOrEmpty(activity.getId())){
				String activityId = KeyGenerator.instance().genKey();
				activity.setId(activityId);
			}
			packActivity(param, activity);
			this.daoHelper.insertRecord(statementId, param);
		}
		
		sqlNameSpace = "WF_TRANSITION";
		List<Transition> transionList = process.getTransitionList();
		for (int i=0;i < transionList.size();i++){
			param = new DataParam();
			Transition transition = transionList.get(i);
			transition.setProcessId(processId);
			statementId = sqlNameSpace+"."+"insertTransition";			
			if (StringUtil.isNullOrEmpty(transition.getId())){
				String transitionId = KeyGenerator.instance().genKey();
				transition.setId(transitionId);				
			}
			packTransition(param, transition);
			this.daoHelper.insertRecord(statementId, param);
		}
	}
	public List<Activity> findActivities(String processId){
		List<Activity> result = new ArrayList<Activity>();
		String sqlNameSpace = "WF_ACTIVITY";
		String statementId = sqlNameSpace+"."+"findActivities";
		DataParam param = new DataParam();
		param.put("WFP_ID",processId);
		List<DataRow> dataRows = this.daoHelper.queryRecords(statementId, param);
		for (int i=0;i < dataRows.size();i++){
			DataRow dataRow = dataRows.get(i);
			Activity activity = new Activity();
			activity.setId(dataRow.getString("WFA_ID"));
			activity.setProcessId(dataRow.getString("WFP_ID"));
			activity.setCode(dataRow.getString("WFA_CODE"));
			activity.setName(dataRow.getString("WFA_NAME"));
			activity.setDesc(dataRow.getString("WFA_DESC"));
			activity.setActType(dataRow.getString("WFA_TYPE"));
			activity.setBusinessURL(dataRow.getString("WFA_BIZ_URL"));
			activity.setMobileBizURL(dataRow.getString("WFA_MBIZ_URL"));
			result.add(activity);
		}
		return result;
	}
	private Activity findActivity(List<Activity> activities,String id){
		Activity result = null;
		for (int i=0;i < activities.size();i++){
			Activity activity = activities.get(i);
			if (id.equals(activity.getId())){
				result = activity;
				break;
			}
		}
		return result;
	}
	
	public List<Transition> findTransitions(String processId,List<Activity> activities){
		List<Transition> result = new ArrayList<Transition>();
		String sqlNameSpace = "WF_TRANSITION";
		String statementId = sqlNameSpace+"."+"findTransitions";
		DataParam param = new DataParam();
		param.put("WFP_ID",processId);
		List<DataRow> dataRows = this.daoHelper.queryRecords(statementId, param);
		
		for (int i=0;i < dataRows.size();i++){
			DataRow dataRow = dataRows.get(i);
			Transition transition = new Transition();
			transition.setId(dataRow.getString("WFT_ID"));
			String fromActivityId = dataRow.getString("WFA_SID");
			String toActivityId = dataRow.getString("WFA_EID");
			Activity fromActivity = findActivity(activities, fromActivityId);
			transition.setFromActivity(fromActivity);
			Activity toActivity = findActivity(activities, toActivityId);
			transition.setToActivity(toActivity);
			
			transition.setProcessId(dataRow.getString("WFP_ID"));
			transition.setCode(dataRow.getString("WFT_CODE"));
			transition.setName(dataRow.getString("WFT_NAME"));
			transition.setDesc(dataRow.getString("WFT_DESC"));
			transition.setTransType(dataRow.getString("WFT_TYPE"));
			result.add(transition);
		}
		return result;
	}
	
	private void packProcess(DataParam param,Process proces,boolean isInsert){
		param.put("WFP_ID", proces.getId());
		param.put("WFP_CODE", proces.getCode());
		param.put("WFP_NAME", proces.getName());
		param.put("WFP_DESC", proces.getDesc());
		
		if (isInsert){
			param.put("WFP_STATE", proces.getStatus());
			param.put("WFP_VERSION", proces.getVersion());
			param.put("WFP_CREATE_TIME", DateUtil.getDate(proces.getCreateTime()));
			param.put("WFP_CREATER", proces.getCreaterId());
			param.put("WFP_MODIFY_TIME", DateUtil.getDate(proces.getModifyTime()));
			param.put("WFP_MODIFIER", proces.getModifier());
			param.put("WFP_GROUP", proces.getGroup());			
		}
		
		param.put("WFP_DEFINE", proces.getDefineXML());
		param.put("WFP_GRAPH", proces.getGraphJSON());
		
	}
	private void packActivity(DataParam param,Activity activity){
		param.put("WFA_ID", activity.getId());
		param.put("WFP_ID", activity.getProcessId());
		param.put("WFA_CODE", activity.getCode());
		param.put("WFA_NAME", activity.getName());
		param.put("WFA_DESC", activity.getDesc());
		param.put("WFA_TYPE", activity.getActType());
		param.put("WFA_BIZ_URL", activity.getBusinessURL());
		param.put("WFA_MBIZ_URL", activity.getMobileBizURL());
	}

	private void packTransition(DataParam param,Transition transition){
		Activity fromActivity = transition.getFromActivity();
		Activity toActivity = transition.getToActivity();
		if (toActivity == null)
			toActivity = new Activity();
		param.put("WFT_ID", transition.getId());
		param.put("WFA_SID", fromActivity.getId());
		param.put("WFA_EID", toActivity.getId());
		param.put("WFP_ID", transition.getProcessId());
		param.put("WFT_CODE", transition.getCode());
		param.put("WFT_NAME", transition.getName());
		param.put("WFT_DESC", transition.getDesc());
		param.put("WFT_TYPE", transition.getTransType());
	}
}
